块、Proc 和 Lambda

在 Ruby 中,块、Proc 和 Lambda 是处理代码块的重要工具。它们允许你将代码块作为参数传递给方法,从而实现更灵活和可重用的代码结构。本教程将详细介绍这些概念,并通过代码示例和实践练习帮助你掌握它们。

1. 块 (Blocks)

块是 Ruby 中最基本的代码块形式。它们可以被传递给方法,并在方法内部执行。块通常用 do...end 或 {...} 来定义。

1.1 基本语法

# 使用 do...end 定义块
[1, 2, 3].each do |num|
  puts num
end

# 使用 {...} 定义块
[1, 2, 3].each { |num| puts num }

1.2 块的参数

块可以接受参数,这些参数在块定义时用 |...| 括起来。

[1, 2, 3].each do |num|
  puts num * 2
end

1.3 块的返回值

块的返回值是块中最后一个表达式的值。

result = [1, 2, 3].map do |num|
  num * 2
end
puts result # 输出: [2, 4, 6]

2. Proc

Proc 是 Ruby 中的一种对象,它封装了一个代码块,并可以在需要时执行。Proc 对象可以被传递、存储和多次调用。

2.1 创建 Proc

你可以使用 Proc.new 或 proc 方法来创建一个 Proc 对象。

my_proc = Proc.new do |num|
  num * 2
end

# 或者
my_proc = proc do |num|
  num * 2
end

2.2 调用 Proc

你可以使用 call 方法来调用 Proc 对象。

result = my_proc.call(3)
puts result # 输出: 6

2.3 Proc 与块的结合

你可以将 Proc 对象作为块传递给方法。

[1, 2, 3].map(&my_proc) # 输出: [2, 4, 6]

3. Lambda

Lambda 是 Proc 的一种特殊形式,它在语法和行为上与 Proc 有一些不同。Lambda 更接近于方法,它对参数的数量有严格的检查。

3.1 创建 Lambda

你可以使用 lambda 或 -> 来创建一个 Lambda 对象。

my_lambda = lambda do |num|
  num * 2
end

# 或者
my_lambda = ->(num) { num * 2 }

3.2 调用 Lambda

你可以使用 call 方法来调用 Lambda 对象。

result = my_lambda.call(3)
puts result # 输出: 6

3.3 Lambda 与 Proc 的区别

  • 参数检查:Lambda 对参数数量有严格的检查,而 Proc 则不会。
  • 返回行为:在 Lambda 中,return 只会从 Lambda 本身返回,而在 Proc 中,return 会从定义 Proc 的上下文中返回。
def test_proc
  my_proc = Proc.new { return 10 }
  my_proc.call
  20
end

def test_lambda
  my_lambda = lambda { return 10 }
  my_lambda.call
  20
end

puts test_proc   # 输出: 10
puts test_lambda # 输出: 20

4. 实践练习

练习 1: 使用块计算数组元素的平方

编写一个方法 square_elements,它接受一个数组和一个块,并使用块计算数组中每个元素的平方。

def square_elements(array)
  array.map { |num| yield(num) }
end

result = square_elements([1, 2, 3]) { |num| num ** 2 }
puts result # 输出: [1, 4, 9]

练习 2: 使用 Proc 过滤数组

编写一个方法 filter_array,它接受一个数组和一个 Proc 对象,并使用 Proc 对象过滤数组中的元素。

def filter_array(array, &block)
  array.select(&block)
end

is_even = proc { |num| num.even? }
result = filter_array([1, 2, 3, 4], &is_even)
puts result # 输出: [2, 4]

练习 3: 使用 Lambda 计算阶乘

编写一个 Lambda 对象 factorial,它接受一个整数并返回该整数的阶乘。

factorial = ->(n) { (1..n).reduce(1, :*) }

puts factorial.call(5) # 输出: 120

5. 总结

块、Proc 和 Lambda 是 Ruby 中处理代码块的重要工具。块是最基本的代码块形式,Proc 是封装代码块的对象,而 Lambda 是 Proc 的一种特殊形式,具有更严格的参数检查和返回行为。通过掌握这些概念,你可以编写更灵活和可重用的代码。

希望这篇教程能帮助你更好地理解块、Proc 和 Lambda,并在实际编程中应用它们。继续练习和探索,你将能够更深入地掌握这些强大的 Ruby 特性。